package presentacion;

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;

import java.awt.BorderLayout;

import javax.swing.JLabel;

import java.awt.Font;

import javax.swing.border.TitledBorder;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.JButton;
import javax.swing.JTextField;

import dominio.Estado;
import dominio.Frontera;
import dominio.NodoBusqueda;
import dominio.Problema;
import dominio.Util;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

import javax.swing.JRadioButton;
import javax.swing.ButtonGroup;

import java.awt.Toolkit;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;

import javax.swing.JCheckBox;
import javax.swing.JTextArea;

public class Interfaz {

	private JFrame VentanaInterfaz;
	private JPanel pnlGlobal;
	private JLabel lblCoordenadax;
	private JLabel lblCoordenadax_1;
	private JLabel lblCoordenaday;
	private JLabel lblCoordenaday_1;
	private JLabel lblbienvenidoIntroduzcaLas;
	private JLabel lblParaCalcularLas;
	private JPanel pnlInicial;
	private JPanel pnlDestino;
	private JLabel lblEstadoInicial;
	private JLabel lblEstadoDestino;
	private JButton btnCalcular;
	private static JTextField txtCoorXi;
	private static JTextField txtCoorYi;
	private static JTextField txtCoorXd;
	private static JTextField txtCoorYd;
	int eOx, eOy, eDx, eDy;
	int[] dato;
	private JPanel panel;
	private JLabel lblSeleccioneEstrategia;
	static JRadioButton rdbtnA;
	static JRadioButton rdbtnAnchura;
	static JRadioButton rdbtnCostoUniforme;
	static JRadioButton rdbtnProfundidad;
	static JRadioButton rdbtnVoraz;
	static final ButtonGroup buttonGroup = new ButtonGroup();
	private JLabel lblProfundidadMxima;
	static JTextField tfProfundidad;
	private static JCheckBox chckbxoptimizado;
	static long nodos_insertados;
	private static JTextArea taResultados;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Interfaz window = new Interfaz();
					window.VentanaInterfaz.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public Interfaz() {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		VentanaInterfaz = new JFrame();
		VentanaInterfaz.setResizable(false);
		VentanaInterfaz.setIconImage(Toolkit.getDefaultToolkit().getImage(Interfaz.class.getResource("/presentacion/32266.png")));
		VentanaInterfaz.setTitle("Calculador de rutas");
		VentanaInterfaz.setBounds(100, 100, 501, 400);
		VentanaInterfaz.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		{
			pnlGlobal = new JPanel();
			VentanaInterfaz.getContentPane()
					.add(pnlGlobal, BorderLayout.CENTER);
			pnlGlobal.setLayout(null);
			{
				lblbienvenidoIntroduzcaLas = new JLabel("¡Bienvenido!");
				lblbienvenidoIntroduzcaLas
						.setHorizontalAlignment(SwingConstants.CENTER);
				lblbienvenidoIntroduzcaLas.setFont(new Font("Tahoma",
						Font.BOLD, 20));
				lblbienvenidoIntroduzcaLas.setBounds(12, 13, 477, 20);
				pnlGlobal.add(lblbienvenidoIntroduzcaLas);
			}
			{
				lblParaCalcularLas = new JLabel(
						"Introduzca los datos necesarios para calcular las rutas");
				lblParaCalcularLas.setHorizontalAlignment(SwingConstants.CENTER);
				lblParaCalcularLas.setFont(new Font("Tahoma", Font.BOLD, 14));
				lblParaCalcularLas.setBounds(12, 40, 477, 16);
				pnlGlobal.add(lblParaCalcularLas);
			}
			{
				pnlInicial = new JPanel();
				pnlInicial.setBorder(new TitledBorder(UIManager
						.getBorder("TitledBorder.border"), "",
						TitledBorder.LEADING, TitledBorder.TOP, null, null));
				pnlInicial.setBounds(12, 69, 223, 83);
				pnlGlobal.add(pnlInicial);
				pnlInicial.setLayout(null);
				{
					lblCoordenadax = new JLabel("CoordenadaX:");
					lblCoordenadax.setBounds(12, 23, 98, 16);
					pnlInicial.add(lblCoordenadax);
					lblCoordenadax.setFont(new Font("Tahoma", Font.PLAIN, 14));
				}
				{
					lblCoordenaday = new JLabel("CoordenadaY:");
					lblCoordenaday.setBounds(12, 54, 98, 16);
					pnlInicial.add(lblCoordenaday);
					lblCoordenaday.setFont(new Font("Tahoma", Font.PLAIN, 14));
				}
				{
					lblEstadoInicial = new JLabel("Estado inicial:");
					lblEstadoInicial
							.setHorizontalAlignment(SwingConstants.CENTER);
					lblEstadoInicial.setFont(new Font("Tahoma", Font.BOLD, 14));
					lblEstadoInicial.setBounds(0, 0, 176, 16);
					pnlInicial.add(lblEstadoInicial);
				}
				{
					txtCoorXi = new JTextField();
					txtCoorXi.setBounds(106, 21, 105, 22);
					pnlInicial.add(txtCoorXi);
					txtCoorXi.setColumns(10);
				}
				{
					txtCoorYi = new JTextField();
					txtCoorYi.setColumns(10);
					txtCoorYi.setBounds(106, 52, 105, 22);
					pnlInicial.add(txtCoorYi);
				}
			}
			{
				pnlDestino = new JPanel();
				pnlDestino.setBorder(new TitledBorder(UIManager
						.getBorder("TitledBorder.border"), "",
						TitledBorder.LEADING, TitledBorder.TOP, null, null));
				pnlDestino.setBounds(247, 71, 223, 81);
				pnlGlobal.add(pnlDestino);
				pnlDestino.setLayout(null);
				{
					lblCoordenadax_1 = new JLabel("CoordenadaX:");
					lblCoordenadax_1.setBounds(12, 24, 98, 16);
					pnlDestino.add(lblCoordenadax_1);
					lblCoordenadax_1
							.setFont(new Font("Tahoma", Font.PLAIN, 14));
				}
				{
					lblCoordenaday_1 = new JLabel("CoordenadaY:");
					lblCoordenaday_1.setBounds(12, 55, 98, 16);
					pnlDestino.add(lblCoordenaday_1);
					lblCoordenaday_1
							.setFont(new Font("Tahoma", Font.PLAIN, 14));
				}
				{
					lblEstadoDestino = new JLabel("Estado destino:");
					lblEstadoDestino
							.setHorizontalAlignment(SwingConstants.CENTER);
					lblEstadoDestino.setFont(new Font("Tahoma", Font.BOLD, 14));
					lblEstadoDestino.setBounds(0, 0, 176, 16);
					pnlDestino.add(lblEstadoDestino);
				}
				{
					txtCoorXd = new JTextField();
					txtCoorXd.setColumns(10);
					txtCoorXd.setBounds(106, 22, 105, 22);
					pnlDestino.add(txtCoorXd);
				}
				{
					txtCoorYd = new JTextField();
					txtCoorYd.setColumns(10);
					txtCoorYd.setBounds(106, 53, 105, 22);
					pnlDestino.add(txtCoorYd);
				}
			}
			{
				btnCalcular = new JButton("Calcular");
				btnCalcular.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						try {
							inicializarPrograma();
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				});
				btnCalcular.setFont(new Font("Tahoma", Font.BOLD, 15));
				btnCalcular.setBounds(349, 225, 111, 27);
				pnlGlobal.add(btnCalcular);
			}
			{
				panel = new JPanel();
				panel.setBorder(new TitledBorder(null, "", TitledBorder.LEADING, TitledBorder.TOP, null, null));
				panel.setBounds(12, 165, 195, 175);
				pnlGlobal.add(panel);
				panel.setLayout(null);
				{
					lblSeleccioneEstrategia = new JLabel("Seleccione estrategia:");
					lblSeleccioneEstrategia.setFont(new Font("Tahoma", Font.BOLD, 15));
					lblSeleccioneEstrategia.setBounds(12, 0, 183, 29);
					panel.add(lblSeleccioneEstrategia);
				}
				{
					rdbtnA = new JRadioButton("A");
					buttonGroup.add(rdbtnA);
					rdbtnA.setBounds(12, 25, 127, 25);
					panel.add(rdbtnA);
				}
				{
					rdbtnAnchura = new JRadioButton("Anchura");
					buttonGroup.add(rdbtnAnchura);
					rdbtnAnchura.setBounds(12, 53, 127, 25);
					panel.add(rdbtnAnchura);
				}
				{
					rdbtnCostoUniforme = new JRadioButton("Costo uniforme");
					buttonGroup.add(rdbtnCostoUniforme);
					rdbtnCostoUniforme.setBounds(12, 82, 127, 25);
					panel.add(rdbtnCostoUniforme);
				}
				{
					rdbtnProfundidad = new JRadioButton("Profundidad");
					buttonGroup.add(rdbtnProfundidad);
					rdbtnProfundidad.setBounds(12, 112, 127, 25);
					panel.add(rdbtnProfundidad);
				}
				{
					rdbtnVoraz = new JRadioButton("Voraz");
					buttonGroup.add(rdbtnVoraz);
					rdbtnVoraz.setBounds(12, 142, 127, 25);
					panel.add(rdbtnVoraz);
				}
			}
			{
				lblProfundidadMxima = new JLabel("Profundidad máxima:");
				lblProfundidadMxima.setFont(new Font("Tahoma", Font.PLAIN, 15));
				lblProfundidadMxima.setBounds(247, 165, 154, 16);
				pnlGlobal.add(lblProfundidadMxima);
			}
			{
				tfProfundidad = new JTextField();
				tfProfundidad.setBounds(400, 163, 70, 22);
				pnlGlobal.add(tfProfundidad);
				tfProfundidad.setColumns(10);
			}
			{
				chckbxoptimizado = new JCheckBox("¿Optimizado?");
				chckbxoptimizado.setFont(new Font("Tahoma", Font.PLAIN, 15));
				chckbxoptimizado.setBounds(247, 190, 123, 25);
				pnlGlobal.add(chckbxoptimizado);
			}
			{
				taResultados = new JTextArea();
				taResultados.setBorder(new TitledBorder(null, "Resultado:", TitledBorder.LEADING, TitledBorder.TOP, null, null));
				taResultados.setBounds(218, 255, 257, 95);
				pnlGlobal.add(taResultados);
			}
		}
		{
		
		}
	}
public static void inicializarPrograma() throws Exception {
		
		//Declaración e inicialización de variables.
		String fname = "Datos.h5";
		String[] vecHojas = { "Archivos/MDT25-0711-H30.asc", "Archivos/MDT25-0712-H30.asc","Archivos/MDT25-0736-H30.asc", "Archivos/MDT25-0737-H30.asc" };
		int  profMax;
		List<NodoBusqueda> solucion; /* Lista que contendria la solucion, es decir, la secuencia.*/
		Scanner leer =new Scanner(System.in);
		Problema p;
		long tiempo_inicial,tiempo_final;
		String estrategia;
		boolean optimizacion;
		//Para más tarde generar el fichero
		FileWriter fichero =new FileWriter("solucion.txt");
	    PrintWriter pw = new PrintWriter(fichero);
		
		//Creamos el archivo H5.
		Util.createFile(fname, vecHojas);
		//Creación del problema 
		p=recogerDatosProblema();
		estrategia=estrategiaSelect();
		optimizacion=chckbxoptimizado.isSelected();
		profMax=Integer.parseInt(tfProfundidad.getText());
		if(optimizacion){
			Util.generarMatricesOptimizacion(p);
		}
		//Busqueda de solución según la estrategia seleccionada y la profundidad máxima
		tiempo_inicial=System.currentTimeMillis();
		solucion=Busqueda(p,estrategia,profMax,optimizacion);
		tiempo_final=System.currentTimeMillis();
		
		//Imprimir solución
		if(!solucion.isEmpty()){
			imprimirSolucion(solucion,pw,tiempo_final-tiempo_inicial,estrategia);
		}else{
			imprimirNoSolucion(pw,tiempo_final-tiempo_inicial,estrategia,profMax);
			}
		taResultados.setText("Ha terminado la ejecución del programa,\nlos resultados se encuentran en el archivo: \n\tSolucion.txt");
		fichero.close();
		leer.close();
	}
	public static List<NodoBusqueda> Busqueda(Problema p,String e,int max_prof,boolean optimizacion) throws Exception{
		Frontera f=new Frontera();
		boolean haySolucion;
		List<Estado> LS;
		List<NodoBusqueda> LN;
		NodoBusqueda nodo_actual = null;
		List<NodoBusqueda> solucion = new ArrayList<NodoBusqueda>();
		NodoBusqueda nodo_inicial=new NodoBusqueda(0,null,p.getEstInicial(),"",0,false,0);
		
		f.insertarNodo(nodo_inicial);
		haySolucion=false;
		while(!haySolucion && !f.esVacia()){
			nodo_actual=f.seleccionarNodo();
			if(p.Meta(nodo_actual.getEstado())){
				haySolucion=true;
			}else{
				if(nodo_actual.getProf()<max_prof){
					LS=Util.Sucesor(nodo_actual.getEstado());
					Collections.shuffle(LS);//Para no seguir siempre el mismo orden al insertar la frontera (sesgo)	
					LN=Util.CrearListaNodosArbol(LS, e, nodo_actual,p,optimizacion);
					f.insertarLista(LN);
					
				}
			}
		}
		if(haySolucion){
			solucion=Util.crearSolucion(nodo_actual);
		}
		nodos_insertados=f.nodosInsertados();
		
		return solucion;	
	}
	public static Problema recogerDatosProblema() throws Exception{
		int eOx, eOy, eDx, eDy;
		int[] dato;
			//Datos del estado inicial.
			eOx=Integer.parseInt(txtCoorXi.getText());
			eOy=Integer.parseInt(txtCoorYi.getText());
			dato=Util.lugarGeografico(eOx,eOy);
			double altitud=Util.altitud(dato[0],dato[1],dato[2]);
			//Creamos el estado inicial.
			Estado e=new Estado(dato[0],dato[1],dato[2],altitud,"");
			//Datos del estado destino.
			eDx=Integer.parseInt(txtCoorXd.getText());
			eDy=Integer.parseInt(txtCoorYd.getText());
			dato=Util.lugarGeografico(eDx, eDy);
			altitud=Util.altitud(dato[0],dato[1],dato[2]);
			//Creamos el estado destino.
			Estado ef=new Estado(dato[0],dato[1],dato[2],altitud,"");
	
		return new Problema(null, e, ef);
	}
	public static String estrategiaSelect(){
		String estrategia=null;
		if(rdbtnA.isSelected()){
			estrategia="A";
		}else if(rdbtnAnchura.isSelected()){
			estrategia="anchura";
		}else if(rdbtnCostoUniforme.isSelected()){
			estrategia="uniforme";
		}else if(rdbtnProfundidad.isSelected()){
			estrategia="profundidad";
		}else if(rdbtnVoraz.isSelected()){
			estrategia="voraz";
		}
		return estrategia;
	}
	
	public static void imprimirNoSolucion(PrintWriter pw,long tiempo,String e,int profMax){
		long minutos,segundos,milisegundos;
		minutos=tiempo/60000;
		segundos=(tiempo-minutos*60000)/1000;
		milisegundos=tiempo-(minutos*60000+segundos*1000);
		pw.println("No se ha encontrado ninguna solución para profundidad "+profMax+" y estrategia "+e+".");
		pw.println("Tiempo total: "+minutos+" minutos "+segundos+" segundos "+milisegundos+" milisegundos.");
		pw.println("Numero total de nodos insertados: "+nodos_insertados);
	}
	
	public static void imprimirSolucion(List<NodoBusqueda> s,PrintWriter pw,long tiempo,String e){
		NodoBusqueda n = null;
		long minutos,segundos,milisegundos;
		minutos=tiempo/60000;
		segundos=(tiempo-minutos*60000)/1000;
		milisegundos=tiempo-(minutos*60000+segundos*1000);
		n=s.get(0);
		pw.println(n.getCosto()+" "+n.getProf()+" "+minutos+":"+segundos+":"+milisegundos);
		for(int i=s.size()-1;i>0;i--){
			n=s.get(i);
			pw.println(n.getEstado().imprimirEstado());
		}		
	}
}
